home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software written by Ken Arnold and
- * published in UNIX Review, Vol. 6, No. 8.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement: ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #if defined(LIBC_SCCS) && !defined(lint)
- static char sccsid[] = "@(#)popen.c 5.14 (Berkeley) 6/1/90";
- #endif /* LIBC_SCCS and not lint */
-
- #include <sys/param.h>
- #include <sys/signal.h>
- #include <sys/wait.h>
- #include <errno.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <paths.h>
- #include <stdlib.h>
-
- /*
- * Original popen() code extended to open both
- * read and write pipes to a process.
- *
- * By Kevin Russo SFA, Inc/US Naval Research Lab, Code 5133
- * March 14, 1991
- *
- * Calling sequence:
- * FILE ** popen_rw(const char *program)
- *
- * Arguments:
- * program - a shell command
- *
- * Returns:
- * FILE **ptr;
- *
- * ptr[0] is a FILE pointer to the program's stdout (read here)
- * ptr[1] is a FILE pointer to the program's stdin (write here)
- *
- * Opens a read fd and a write fd, so popen()'s 'type'argument
- * is not necessary.
- */
-
- static pid_t *pids;
-
- FILE **
- popen_rw(const char *program)
- {
- FILE **iop;
- int pdes[2], fds, pid;
- int pdes2[2];
-
- if (pids == NULL) {
- if ((fds = getdtablesize()) <= 0)
- return (NULL);
- if((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
- return (NULL);
- bzero((char *)pids, fds * sizeof(pid_t));
- }
- if ((iop = (FILE **) malloc(2 * sizeof(FILE **))) == NULL)
- return (NULL);
-
- if (pipe(pdes) < 0 || pipe(pdes2) < 0)
- return (NULL);
- switch (pid = fork()) {
- case -1: /* error */
- (void) close(pdes[0]);
- (void) close(pdes[1]);
- (void) close(pdes2[0]);
- (void) close(pdes2[1]);
- return (NULL);
- /* NOTREACHED */
- case 0: /* child */
- if (pdes[1] != STDOUT_FILENO) {
- (void) dup2(pdes[1], STDOUT_FILENO);
- (void) close(pdes[1]);
- }
- (void) close(pdes[0]);
- if (pdes2[0] != STDIN_FILENO) {
- (void) dup2(pdes2[0], STDIN_FILENO);
- (void) close(pdes2[0]);
- }
- (void) close(pdes2[1]);
- execl(_PATH_BSHELL, "sh", "-c", program, NULL);
- _exit(127);
- /* NOTREACHED */
- }
- /* parent; assume fdopen can't fail... */
- iop[0] = fdopen(pdes[0], "r");
- iop[1] = fdopen(pdes2[1], "w");
- (void) close(pdes[1]);
- (void) close(pdes2[0]);
- pids[fileno(iop[0])] = pid;
- pids[fileno(iop[1])] = pid;
- return (iop);
- }
-
- int pclose_rw(FILE *iop[])
- {
- register int fdes,fdes2;
- int omask;
- /*union wait pstat;*/
- int pstat;
- pid_t pid;
-
- /*
- * pclose returns -1 if stream is not associated with a
- * `popened' command, if already `pclosed', or waitpid
- * returns an error.
- */
- if (pids == NULL || pids[fdes = fileno(iop[0])] == 0 ||
- pids[fdes2 = fileno(iop[1])] == 0)
- return (-1);
- (void) fclose(iop[0]);
- (void) fclose(iop[1]);
- omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
- do {
- pid = waitpid(pids[fdes], &pstat, 0);
- } while (pid == -1 && errno == EINTR);
- (void) sigsetmask(omask);
- pids[fdes] = 0;
- pids[fdes2] = 0;
- /*return (pid == -1 ? -1 : pstat.w_status);*/
- return (pid == -1 ? -1 : pstat);
- }
-